// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.util.FnvHash;

// import java.util.List;
// import java.util.concurrent.ConcurrentHashMap;
// import java.util.concurrent.ConcurrentMap;

#include "InsertColumnsCache.h"
#include "../../utils/BOOL.h"
#include "../../utils/FnvHash.h"

InsertColumnsCache_Entry::InsertColumnsCache_Entry(
    long hashCode64,
    string_ptr columnsString,
    string_ptr columnsFormattedString,
    SQLExpr_list_ptr columns,
    InsertColumnsCache_Entry_ptr next)
{
  this->hashCode64 = hashCode64;
  this->columnsString = columnsString;
  this->columnsFormattedString = columnsFormattedString;
  this->columnsFormattedStringHash = FnvHash::fnv1a_64_lower(columnsFormattedString);
  this->columns = columns;
  this->next = next;
}

InsertColumnsCache_ptr InsertColumnsCache::global = InsertColumnsCache_ptr(new InsertColumnsCache(8192));

InsertColumnsCache::InsertColumnsCache(int tableSize)
{
  this->indexMask = tableSize - 1;
  this->buckets = std::make_shared<std::list<InsertColumnsCache_Entry_ptr>>();
  for (int i = 0; i <= this->indexMask; i++)
  {
    this->buckets->push_back(nullptr);
  }
}

InsertColumnsCache_Entry_ptr InsertColumnsCache::get(long hashCode64)
{
  int bucket = ((int)hashCode64) & indexMask;

  auto it_buckets = buckets->begin();
  std::advance(it_buckets, bucket);
  for (InsertColumnsCache_Entry_ptr entry = *it_buckets; entry != nullptr; entry = entry->next)
  {
    if (hashCode64 == entry->hashCode64)
    {
      return entry;
    }
  }

  return nullptr;
}

BOOL_ptr InsertColumnsCache::put(long hashCode64, string_ptr columnsString, string_ptr columnsFormattedString, SQLExpr_list_ptr columns)
{
  int bucket = ((int)hashCode64) & indexMask;

  auto it_buckets = buckets->begin();
  std::advance(it_buckets, bucket);
  for (InsertColumnsCache_Entry_ptr entry = *it_buckets; entry != nullptr; entry = entry->next)
  {
    if (hashCode64 == entry->hashCode64)
    {
      return BOOL::TRUE;
    }
  }

  std::advance(it_buckets, bucket);
  InsertColumnsCache_Entry_ptr entry =
      InsertColumnsCache_Entry_ptr(
          new InsertColumnsCache_Entry(
              hashCode64,
              columnsString,
              columnsFormattedString,
              columns,
              (*it_buckets)));
  (*it_buckets) = entry; // 并发是处理时会可能导致缓存丢失，但不影响正确性

  return BOOL::FALSE;
}
